package com.atguigu.gmall.order.receiver;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.enums.model.OrderStatus;
import com.atguigu.gmall.enums.model.ProcessStatus;
import com.atguigu.gmall.order.model.OrderInfo;
import com.atguigu.gmall.order.service.OrderInfoService;
import com.rabbitmq.client.Channel;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 接收消息
 */
@Slf4j
@Component
@SuppressWarnings("all")
public class OrderReceiver {

    @Autowired
    private OrderInfoService orderInfoService;
    @Autowired
    private RedisTemplate redisTemplate;

    @SneakyThrows
    @RabbitListener(queues = MqConst.QUEUE_ORDER_CANCEL)
    public void processOrderClose(Long orderId, Channel channel, Message message){
        if(orderId != null){
            log.info("[订单服务]监听关单消息,数据:{}",orderId);
            //调业务关单
            OrderInfo orderInfo = orderInfoService.getById(orderId);
            //只有订单在未支付状态才会执行关单
            if(orderInfo != null
                    && OrderStatus.UNPAID.name().equals(orderInfo.getOrderStatus())
                    && OrderStatus.UNPAID.name().equals(orderInfo.getProcessStatus())){
                orderInfoService.execExpiredOrder(orderId);
            }
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }

    /**
     * 监听用户支付成功消息,修改订单状态,发送锁定消息锁定库存
     * @param orderId 订单id
     * @param channel 消息通道
     * @param message 发送消息
     */
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_PAYMENT_PAY,durable = "true"),
            value = @Queue(value = MqConst.QUEUE_PAYMENT_PAY,durable = "true"),
            key = MqConst.ROUTING_PAYMENT_PAY
    ))
    public void processSuccessResult(Long orderId,Channel channel,Message message){
        try {
            if(orderId != null){
                log.info("[订单微服务]监听用户支付成功消息,订单ID:{}",orderId);
                //保证幂等性
                String key = "orderId" + orderId + "stockrecord";
                Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, null, 1, TimeUnit.HOURS);
                if(flag){

                    //1.根据订单i查询订单记录
                    OrderInfo orderInfo = orderInfoService.getOrderInfoByOrderId(orderId);
                    if(orderInfo != null && ProcessStatus.UNPAID.name().equals(orderInfo.getOrderStatus())){
                        //2.更新订单支付状态:已支付
                        orderInfoService.updateOrderStatus(orderId, ProcessStatus.PAID);
                        //3.todo 发消息到第三方库存系统,锁定库存商品
                        orderInfoService.sendDeductLockMsg(orderId);
                    }
                }
            }
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        } catch (Exception e) {
            //todo 重新入队,MQ再次发消息,做好最大次数限制,做好幂等性
           log.error("[订单微服务]监听用户支付消息成功,处理失败:{}",e);
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false,true);
            throw new RuntimeException(e);
        }
    }


    /**
     * 监听库存系统,锁定商品库结果
     * @param deductResultJsonStr
     * @param channel
     * @param message
     */
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_WARE_ORDER,durable = "true"),
            value = @Queue(value = MqConst.QUEUE_WARE_ORDER,durable = "true"),
            key = MqConst.ROUTING_WARE_ORDER
    ))
    public void processDeductResult(String deductResultJsonStr,Channel channel,Message message){
        try {
            if(StringUtils.isNotBlank(deductResultJsonStr)){
                log.info("[订单服务]监听锁定库存结果:{}",deductResultJsonStr);
                //1.根据锁定库存结果跟新订单状态
                Map<String,String> map = JSON.parseObject(deductResultJsonStr, Map.class);
                String orderId = map.get("orderId");
                String status = map.get("status");
                if(StringUtils.isNotBlank(orderId) && StringUtils.isNotBlank(status)){
                    if("DEDUCTED".equals(status)){
                        //修改订单状态为"待发货
                        orderInfoService.updateOrderStatus(Long.valueOf(orderId),ProcessStatus.WAITING_DELEVER);
                    }
                    if("OUT_OF_STOCK".equals(status)){
                        //修改订单状态为"库存异常"
                        orderInfoService.updateOrderStatus(Long.valueOf(orderId),ProcessStatus.STOCK_EXCEPTION);
                    }
                }
            }
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error("[订单服务]监听锁定库存结果异常:{}",e,deductResultJsonStr);
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
            throw new RuntimeException(e);
        }
    }
}